import os
import re
import sys

from System.Diagnostics import Process



def Main():

    versionTemplate, fileNames = HandleArguments()
    revNr = QueryRevNr(".")
    underTeamCity, buildNr = DetectTeamCityAndBuildNr()
    versionStr = HandleVersion(versionTemplate, revNr, buildNr, underTeamCity)

    for fileName in fileNames:
        PatchKnownFile(fileName, versionStr)



def HandleArguments():

    if len(sys.argv) < 3:                                           
        print "Usage: "                                              
        print "%s version-template assembly-info-1 assembly-info-2 ..." % sys.argv[0]               
        exit(-1)                                                     
                                                                     
    ### Check arguments                                              
      
    versionTemplate = sys.argv[1]                                                                 
    names = sys.argv[2:]

    for name in names:

        if not os.access(name, os.F_OK):                          
            print "File: \"%s\" doesn't exist." % name   
            exit(-2)                                                     
                                                                     
        if not os.access(name, os.R_OK):                          
            print "Could not access file: \"%s\"" % name 
            exit(-2)                                                     
                                                                     
    return (versionTemplate, names)



def HandleVersion(template, rev, build, underTC):

    version = template
    version = re.sub(r'R#', rev.ToString(), version)
    version = re.sub(r'B#', build.ToString(), version)

    print "Version=%s" % version

    if underTC:                                                                    
        print "##teamcity[buildNumber '%s']" % version                               

    return version



def QueryRevNr(vcsDirectory):

    ### Query the revision number                                       
                                                                        
    proc = Process()                                                    
                                                                        
    proc.StartInfo.UseShellExecute = False                              
    proc.StartInfo.RedirectStandardInput = False                        
    proc.StartInfo.RedirectStandardOutput = True                        
    proc.StartInfo.RedirectStandardError = False                        
    proc.StartInfo.FileName = "svn.exe"                                 
    proc.StartInfo.Arguments = "info " + vcsDirectory                   
                                                                        
    proc.Start()                                                        
    proc.WaitForExit()                                                  
                                                                        
    vcsOut = proc.StandardOutput.ReadToEnd()                            
                                                                        
    revLinePattern = re.compile(r"^Last.*Rev:\s*(\d+)\s*$", re.I|re.M)  
    revMatched = revLinePattern.search(vcsOut)                          
    if revMatched:                                                      
        revNr = revMatched.group(1)                                     
    else:                                                               
        revNr = 0                                                       

    return revNr



def DetectTeamCityAndBuildNr():

    underTeamCity = os.environ.get('TEAMCITY_VERSION',"") != ""

    if underTeamCity:
        buildNr = os.environ.get('BUILD_NUMBER','0')
    else:
        buildNr = '0'

    return (underTeamCity, buildNr)



def PatchKnownFile(fileName, version):

    origCopyFileName = fileName + ".orig"
    RenameFile(fileName, origCopyFileName)

    fnamePattern = re.compile(r"^(\S+)\.([^\.\s]+)$")
    m = fnamePattern.match(fileName)
    ok = False
    if m:
        suffix = m.group(2)
        newFileName = m.group(1) + "Ver." + suffix
        if suffix == 'cs':
            verPattern = r"\[assembly:.*(Assembly.*Version)\D*(\d+.\d+.\d+.\d+)\D*.*"
            PatchTextFile(origCopyFileName, fileName, verPattern, 2, version)
            ok = True
        if suffix == 'nuspec':
            verPattern = r".*<version>\D*(\d+.\d+.\d+.\d+)\D*</version>.*"
            PatchTextFile(origCopyFileName, fileName, verPattern, 1, version)
            ok = True
    
    if not ok:
        print "\tunknown file type: %s" % fileName



def RenameFile(src, dst):

    if os.access(dst, os.F_OK):
        os.remove(dst)

    os.rename(src, dst)
    
    if not os.access(dst, os.F_OK):                          
        print "Could not rename %s to %s" % (src,dst)
        exit(-4)



def PatchTextFile(srcFileName, dstFileName, pattern, grp, subst):

    compiledPattern = re.compile(pattern)
                                                                                                    
    etalon_f = open(srcFileName, "r", 1)                                                            
    patched_f = open(dstFileName, "w")                                                              
    changes = 0
    for line in etalon_f:                                                                           
        matched = compiledPattern.match(line)                                                  
        if matched:                                                                                 
           patched_line = line[:matched.start(grp)] + subst + line[matched.end(grp):]             
           patched_f.write(patched_line)                                                            
           changes += 1
        else:                                                                                       
           patched_f.write(line)                                                                    
    patched_f.close()                                                                               
    etalon_f.close()
    
    changesStr = ("%d changes" % changes) if changes >= 2 else "1 change" if changes == 1 else "no changes"
    print "\t%s patched (%s)" % (dstFileName, changesStr)



print "==== Patch version: start ===="

Main()

print "==== Patch version: finished ===="
